/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.export.spc;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intelligent.ispc.common.utils.StringUtils;
import com.intelligent.ispc.core.dto.ControlChartWarningRuleDto;
import com.intelligent.ispc.core.dto.SimpleKeyValueDto;
import com.intelligent.ispc.core.dto.TestItemDto;
import com.intelligent.ispc.external.rcall.common.LevelType;
import com.intelligent.ispc.external.rcall.dto.*;
import com.intelligent.ispc.foundation.poi.*;
import com.intelligent.ispc.utils.Constant;
import com.intelligent.ispc.utils.ExportLabelConstant;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by cherry on 2016/4/19.
 */
public class ExportCellFactory implements ExCellFactory {


    private Integer[] headIndex = new Integer[]{0, 0};
    private Integer[] dataIndex = new Integer[]{9, 0};
    private Integer currentRow = 0;
    private XSSFWorkbook workbook = new XSSFWorkbook();
    private List<ExSheet> sheets = new ArrayList<>();
    private int digNum = 6;
    private Map<String, XSSFCellStyle> cpColorMap = Maps.newHashMap();

    public void buildSPC4SingleItem(Map<String, Object> searchParam, Map<String, Object> results) {
        Map<String, Object> charts = (Map) searchParam.get("exportCharts");
        ExSheet exSheet = new ExSheet();
        exSheet.setName("Charts");

        List<ExCell> cellList = Lists.newArrayList();

        // building head
        List<ExCell> headCellList = buildHead(searchParam);
        List<ExCell> ndcCellList = Lists.newArrayList();
        List<ExCell> rcCellList = Lists.newArrayList();
        List<ExCell> rcCellListAll = Lists.newArrayList();
        cellList.addAll(headCellList);

        if (charts.containsKey(Constant.ANALYSE_NDC_TYPE)) {
            NormalDistributionDto ndcDto = (NormalDistributionDto) results.get(Constant.ANALYSE_NDC_TYPE);
            String filePath = (String) charts.get(Constant.ANALYSE_NDC_TYPE);
            ndcCellList = buildNDC(ndcDto, filePath);
            cellList.addAll(ndcCellList);
        }

        List<ExCell> rcRuleList = buildRuleDescription(results);
        boolean flag = false;

        if (charts.containsKey(Constant.ANALYSE_RUNC_TYPE)) {
            List<RuleResultDto> ruleResultList = ((ControlDataDto) results.get(Constant.ANALYSE_RUNC_TYPE)).getRuleResultList();
            String filePath = (String) charts.get(Constant.ANALYSE_RUNC_TYPE);
            rcCellList = buildRC(ruleResultList, filePath, "Run Chart");
            flag = true;
            rcCellListAll.addAll(rcCellList);
        }

        if (charts.containsKey(Constant.ANALYSE_XBARC_TYPE)) {
            List<RuleResultDto> ruleResultList = ((ControlDataDto) results.get(Constant.ANALYSE_XBARC_TYPE)).getRuleResultList();
            String filePath = (String) charts.get(Constant.ANALYSE_XBARC_TYPE);
            rcCellList = buildRC(ruleResultList, filePath, "X-Bar Chart");
            flag = true;
            rcCellListAll.addAll(rcCellList);
        }

        if (charts.containsKey(Constant.ANALYSE_SDC_TYPE)) {
            List<RuleResultDto> ruleResultList = ((ControlDataDto) results.get(Constant.ANALYSE_SDC_TYPE)).getRuleResultList();
            String filePath = (String) charts.get(Constant.ANALYSE_SDC_TYPE);
            rcCellList = buildRC(ruleResultList, filePath, "SD Chart");
            flag = true;
            rcCellListAll.addAll(rcCellList);
        }

        if (charts.containsKey(Constant.ANALYSE_RC_TYPE)) {
            List<RuleResultDto> ruleResultList = ((ControlDataDto) results.get(Constant.ANALYSE_RC_TYPE)).getRuleResultList();
            String filePath = (String) charts.get(Constant.ANALYSE_RC_TYPE);
            rcCellList = buildRC(ruleResultList, filePath, "R Chart");
            flag = true;
            rcCellListAll.addAll(rcCellList);
        }

        if (charts.containsKey(Constant.ANALYSE_MRC_TYPE)) {
            List<RuleResultDto> ruleResultList = ((ControlDataDto) results.get(Constant.ANALYSE_MRC_TYPE)).getRuleResultList();
            String filePath = (String) charts.get(Constant.ANALYSE_MRC_TYPE);
            rcCellList = buildRC(ruleResultList, filePath, "MR Chart");
            flag = true;
            rcCellListAll.addAll(rcCellList);
        }

        if (flag) {
            cellList.addAll(rcRuleList);
            cellList.addAll(rcCellListAll);
        }
        exSheet.setExCells(cellList);
        sheets.add(exSheet);

        ExSheet exItemSheet = new ExSheet();
        exItemSheet.setName((String) searchParam.get("itemName"));
        double [] mrValue = (double[]) results.get("mrValue");
        String [] xxbarValue = (String[])results.get("xxbarValue");
        List<ExCell> itemsCellList = buildData((List<TestItemDto>) results.get("testItemDtos"), mrValue, xxbarValue);
        exItemSheet.setExCells(itemsCellList);
        sheets.add(exItemSheet);
    }

    public void buildSPCMultiItems(Map<String, Object> searchParam, Map<String, Object> resultData, Map<String, Object> testItems) {

        List<SimpleKeyValueDto> charts = (List) searchParam.get("exportCharts");
        List<ExportBaseObject> baseObjectList = (List)searchParam.get("charts");
        searchParam.remove("exportCharts");
        ExSheet exChartSheet = new ExSheet();
        exChartSheet.setName("Charts");
        exChartSheet.setIndex(1);

        List<ExCell> cellList = Lists.newArrayList();

        // building head
        List<ExCell> headCellList = buildHead(searchParam);
        List<ExCell> ndcCellList = Lists.newArrayList();
        List<ExCell> itemsCellList = Lists.newArrayList();

        cellList.addAll(headCellList);
        for (SimpleKeyValueDto dto : charts) {
            NormalDistributionDto ndcDataDto = (NormalDistributionDto) resultData.get(dto.getKey());
            ndcCellList.addAll(buildNDC(ndcDataDto, (String) dto.getValue()));
        }

        cellList.addAll(ndcCellList);
        exChartSheet.setExCells(cellList);
        sheets.add(exChartSheet);

        int i = 2;
        for (int k=0; k<charts.size(); k++) {
            ExSheet exItemSheet = new ExSheet();
            exItemSheet.setName(charts.get(k).getKey());
            List<TestItemDto> testItemDtoList = (List<TestItemDto>) testItems.get(charts.get(k).getKey());
            double [] mrValue = baseObjectList.get(k).getMrValue();
            String [] xxbarValue = baseObjectList.get(k).getXxbarValue();
            itemsCellList = buildData(testItemDtoList, mrValue, xxbarValue);
            exItemSheet.setExCells(itemsCellList);
            exItemSheet.setIndex(i);

            sheets.add(exItemSheet);
            i++;
        }

    }

    private List<ExCell> buildHead(Map<String, Object> searchParam) {
        String[] searchConditions = ExportLabelConstant.EXPORT_SEARCH_LABELS;
        List<ExCell> exCellList = new ArrayList<>();
        for (int i = 0; i < searchConditions.length; i++) {
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i, headIndex[1]}, searchConditions[i], ExCellType.TEXT, fillTitleStyle()));
        }
        int n = 0;
        exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + n++, headIndex[1] + 1}, searchParam.get("projectName") == null ? "-" : (String) searchParam.get("projectName"), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + n++, headIndex[1] + 1}, searchParam.get("stationId") == null ? "-" : (String) searchParam.get("stationId"), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + n++, headIndex[1] + 1}, searchParam.get("slotNo") == null ? "-" : (String) searchParam.get("slotNo"), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + n++, headIndex[1] + 1}, searchParam.get("serialNumber") == null ? "-" : (String) searchParam.get("serialNumber"), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + n++, headIndex[1] + 1}, searchParam.get("startTime") == null ? "-" : (String) searchParam.get("startTime"), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + n++, headIndex[1] + 1}, searchParam.get("stopTime") == null ? "-" : (String) searchParam.get("stopTime"), ExCellType.TEXT));

        currentRow = searchConditions.length + 1;

        return exCellList;
    }

    private List<ExCell> buildRuleDescription(Map<String, Object> results) {

        List<ControlChartWarningRuleDto> ccRDtoList = (List<ControlChartWarningRuleDto>) results.get("ruleList");
        List<ExCell> exCellList = new ArrayList<>();
        for (int i = 0; i < ccRDtoList.size(); i++) {
            exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + i, dataIndex[1]}, ccRDtoList.get(i).getCode(), ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + i, dataIndex[1] + 1}, ccRDtoList.get(i).getDetailRule(), ExCellType.TEXT));
        }

        currentRow += ccRDtoList.size() + 2;
        return exCellList;
    }

    private List<ExCell> buildNDC(NormalDistributionDto dto, String filePath) {
        String[] labels = ExportLabelConstant.EXPORT_NDC_LABELS;
        List<ExCell> exCellList = new ArrayList<>();

        for (int i = 0; i < labels.length; i++) {
            exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + i, dataIndex[1]}, labels[i], ExCellType.TEXT, fillTitleStyle()));
        }

        StandardDto standardDto = dto.getStaDataItem();
        NormalDistributionStatisticsDto ndsDataDto = dto.getNdsDataItem();
        ProcessCapabilityDto pcDto = dto.getPcDataItem();

        int n = 1;
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getDataCount(), 0) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getAvgValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getMaxValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getMinValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getRangeValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getStdValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getLclValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getUclValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getKurtosisValue(), digNum) + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, formatDouble(ndsDataDto.getSkewnessValue(), digNum) + "", ExCellType.TEXT));

        n = 12;
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, standardDto.getGroupValue() + "", ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, standardDto.getUslValue() == null ? "-" : (formatDouble(standardDto.getUslValue().doubleValue(), digNum) + ""), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, standardDto.getLslValue() == null ? "-" : (formatDouble(standardDto.getLslValue().doubleValue(), digNum) + ""), ExCellType.TEXT));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, standardDto.getCenterValue() == null ? "-" : (formatDouble(standardDto.getCenterValue(), digNum) + ""), ExCellType.TEXT));


        n = 17;
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, (pcDto.getCaData() == null ? "-" : formatDouble(pcDto.getCaData().getValue(), 4) + "%"), ExCellType.TEXT, pcDto.getCaData() == null ? null : fillPcColor(pcDto.getCaData().getgType())));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, (pcDto.getCpkData() == null ? "-" : formatDouble(pcDto.getCpkData().getValue(), digNum) + ""), ExCellType.TEXT, pcDto.getCpkData() == null ? null : fillPcColor(pcDto.getCpkData().getgType())));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, (pcDto.getCpData() == null ? "-" : formatDouble(pcDto.getCpData().getValue(), digNum) + ""), ExCellType.TEXT, pcDto.getCpData() == null ? null : fillPcColor(pcDto.getCpData().getgType())));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, (pcDto.getCplData() == null ? "-" : formatDouble(pcDto.getCplData().getValue(), digNum) + ""), ExCellType.TEXT, pcDto.getCplData() == null ? null : fillPcColor(pcDto.getCplData().getgType())));
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + n++, dataIndex[1] + 1}, (pcDto.getCpuData() == null ? "-" : formatDouble(pcDto.getCpuData().getValue(), digNum) + ""), ExCellType.TEXT, pcDto.getCpuData() == null ? null : fillPcColor(pcDto.getCpuData().getgType())));

        exCellList.add(ExUtil.fillToCell(new Integer[]{0, 0, 1023, 255, dataIndex[1] + 2, currentRow, dataIndex[1] + 5, currentRow + n}, filePath, ExCellType.IMAGE));
        currentRow = currentRow + labels.length + 1;
        return exCellList;
    }

    private List<ExCell> buildRC(List<RuleResultDto> ruleResultList, String filePath, String rcharName) {
        List<ExCell> exCellList = new ArrayList<>();
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow, dataIndex[1]}, rcharName, ExCellType.TEXT, fillTitleStyle()));
        currentRow += 1;
        RuleResultDto ruleResultR1 = ruleResultList.get(0);
        String name = ruleResultR1.getRuleName();
        if (ruleResultR1.isOverRule()) {
            name = "[" + name + "-" + ruleResultR1.getPos() + "]";
        }
        exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow, dataIndex[1]}, name, ExCellType.TEXT, fillRcColor(ruleResultR1.isOverRule())));

        for (int i = 1; i < ruleResultList.size(); i++) {
            String ruleName = "[" + ruleResultList.get(i).getRuleName() + "]";
            boolean isOverRule = ruleResultList.get(i).isOverRule();
            exCellList.add(ExUtil.fillToCell(new Integer[]{currentRow + i, dataIndex[1]}, ruleName, ExCellType.TEXT, fillRcColor(isOverRule)));
        }

        int length = ExportLabelConstant.EXPORT_NDC_LABELS.length;
        exCellList.add(ExUtil.fillToCell(new Integer[]{0, 0, 1023, 255, dataIndex[1] + 2, currentRow - 1, dataIndex[1] + 5, currentRow + length}, filePath, ExCellType.IMAGE));

        currentRow += length + 2;

        return exCellList;
    }

    private List<ExCell> buildData(List<TestItemDto> dtos, double[] mrValue, String[] xxbarValue) {

        String[] itemLabels = ExportLabelConstant.EXPORT_ITEM_LABELS;
        List<ExCell> exCellList = new ArrayList<>();
        for (int i = 0; i < itemLabels.length; i++) {
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0], headIndex[1] + i}, itemLabels[i], ExCellType.TEXT, fillTitleStyle()));
        }

        int j = 0;
        for (int i = 0; i < dtos.size(); i++) {
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1]}, dtos.get(i).getSerialNumber(), ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 1}, dtos.get(i).getUpperLimit(), ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 2}, dtos.get(i).getLowerLimit(), ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 3}, dtos.get(i).getUnitName(), ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 4}, dtos.get(i).getTestedValue(), ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 5}, dtos.get(i).getIsPass() ? "PASS" : "FAIL", ExCellType.TEXT));
            exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 6}, xxbarValue[i], ExCellType.TEXT));
            if (dtos.get(i) != null && dtos.get(i).getIsNumeric() && !isBlank(dtos.get(i).getTestedValue())) {
                exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 7}, formatDouble(mrValue[j], digNum)+"", ExCellType.TEXT));
                j++;
            } else {
                exCellList.add(ExUtil.fillToCell(new Integer[]{headIndex[0] + i + 1, headIndex[1] + 7}, "-", ExCellType.TEXT));
            }
        }
        return exCellList;
    }

    private XSSFCellStyle fillPcColor(String level) {
        return getCpColorMap().get(level);
    }

    private XSSFCellStyle fillRcColor(boolean isOverRule) {
        XSSFCellStyle style = this.getCurrentWorkbook().createCellStyle();
        XSSFFont font = this.getCurrentWorkbook().createFont();
        font.setColor(IndexedColors.BLACK.index);
        if (isOverRule) {
            font.setColor(IndexedColors.RED.index);
        }
        style.setFont(font);
        return style;
    }

    private XSSFCellStyle fillTitleStyle() {
        XSSFCellStyle style = this.getCurrentWorkbook().createCellStyle();
        XSSFFont font = this.getCurrentWorkbook().createFont();
        font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
        style.setFont(font);
        return style;
    }

    private String formatDouble(double str, int dig) {
        return String.format("%." + dig + "f", str);
    }

    public Map<String, XSSFCellStyle> getCpColorMap() {
        if (cpColorMap.size() == 0) {
            XSSFCellStyle style = this.getCurrentWorkbook().createCellStyle();
            XSSFFont font = this.getCurrentWorkbook().createFont();
            font.setColor(IndexedColors.GREEN.index);
            style.setFont(font);
            cpColorMap.put(LevelType.EXCELLENT.toString(), style);

            style = this.getCurrentWorkbook().createCellStyle();
            font = this.getCurrentWorkbook().createFont();
            font.setColor(IndexedColors.BLUE.index);
            style.setFont(font);
            cpColorMap.put(LevelType.GOOD.toString(), style);

            style = this.getCurrentWorkbook().createCellStyle();
            font = this.getCurrentWorkbook().createFont();
            font.setColor(IndexedColors.BLUE_GREY.index);
            style.setFont(font);
            cpColorMap.put(LevelType.ACCEPTABLE.toString(), style);

            style = this.getCurrentWorkbook().createCellStyle();
            font = this.getCurrentWorkbook().createFont();
            font.setColor(IndexedColors.ORANGE.index);
            style.setFont(font);
            cpColorMap.put(LevelType.ABOVE_RECTIFICATION.toString(), style);

            style = this.getCurrentWorkbook().createCellStyle();
            font = this.getCurrentWorkbook().createFont();
            font.setColor(IndexedColors.RED.index);
            style.setFont(font);
            cpColorMap.put(LevelType.RECTIFICATION.toString(), style);
        }

        return cpColorMap;
    }

    @Override
    public XSSFWorkbook getCurrentWorkbook() {
        return workbook;
    }

    @Override
    public List<ExSheet> getSheets() {
        return sheets;
    }

    private boolean isBlank(String d) {
        if (StringUtils.isBlank(d)) {
            return true;
        }

        if (d.equalsIgnoreCase("N/A") || d.equalsIgnoreCase("-")
                || d.equalsIgnoreCase("nil") || d.equalsIgnoreCase("UnKown Line") ||
                d.equalsIgnoreCase("_")) {
            return true;
        }

        return false;
    }
}


